package com.zhuangjie.openfeign.aop.retry;

import com.zhuangjie.openfeign.aop.retry.annotation.FeignRetry;
import com.zhuangjie.openfeign.aop.retry.pool.RetryableThreadPool;
import feign.RetryableException;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * Feign重试处理器
 *
 * @author zhuangjie
 * @date 2023/11/08
 */
@Aspect
@Slf4j
@Component
public class FeignRetryAspect {
    @Autowired
    private RetryableThreadPool retryableThreadPool;

    @Around("@annotation(com.zhuangjie.openfeign.aop.retry.annotation.FeignRetry)")
    public Object retry(ProceedingJoinPoint joinPoint) throws Throwable {
        Method method = getCurrentMethod(joinPoint);
        FeignRetry feignRetry = method.getAnnotation(FeignRetry.class);
        return retryableThreadPool.execute(()->{
            try {
                return joinPoint.proceed(joinPoint.getArgs());
            } catch (Throwable e) {
                throw new RuntimeException(e);
            }
        }, new Class[]{RetryableException.class},feignRetry.maxAttempt(), feignRetry.retryInterval(),(e)->{
            log.info("OpenFeign retry fall！， error info : "+e.getMessage());
        });

    }

    private Method getCurrentMethod(JoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        return signature.getMethod();
    }
}